﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace MvcFckEditor.Components
{
    internal class Config
    {
        //public bool Enabled;
        public string FckBasePath;
        public string UserFilesPath;
        public string[] AllowedTypes;
        public string[] HtmlExtensions;
        public TypeConfigList TypeConfig;

        internal Config()
        {
            DefaultSettings();
        }

        private void DefaultSettings()
        {
            // Initialize all default settings.

            //Enabled = false;
            FckBasePath = "/fckeditor2.3.6/";
            UserFilesPath = FckProvider.Instance().GetUserFilesPath();
            if (UserFilesPath.EndsWith("/"))
            {
                UserFilesPath = UserFilesPath.Substring(0, UserFilesPath.Length - 1);
            }

            if (!Directory.Exists(HttpContext.Current.Server.MapPath(UserFilesPath)))
            {
                Util.CreateDirectory(HttpContext.Current.Server.MapPath(UserFilesPath));
            }
            
            AllowedTypes = new string[] { "File", "Image", "Flash", "Media" };
            HtmlExtensions = new string[] { "html", "htm", "xml", "xsd", "txt", "js" };

            TypeConfig = new TypeConfigList();

            TypeConfig["File"].AllowedExtensions = new string[] { "7z", "aiff", "asf", "avi", "bmp", "csv", "doc", "fla", "flv", "gif", "gz", "gzip", "jpeg", "jpg", "mid", "mov", "mp3", "mp4", "mpc", "mpeg", "mpg", "ods", "odt", "pdf", "png", "ppt", "pxd", "qt", "ram", "rar", "rm", "rmi", "rmvb", "rtf", "sdc", "sitd", "swf", "sxc", "sxw", "tar", "tgz", "tif", "tiff", "txt", "vsd", "wav", "wma", "wmv", "xls", "xml", "zip" };
            TypeConfig["File"].DeniedExtensions = new string[] { };
            TypeConfig["File"].FilesPath = UserFilesPath;

            TypeConfig["Image"].AllowedExtensions = new string[] { "bmp", "gif", "jpeg", "jpg", "png" };
            TypeConfig["Image"].DeniedExtensions = new string[] { };
            TypeConfig["Image"].FilesPath = UserFilesPath;

            TypeConfig["Flash"].AllowedExtensions = new string[] { "swf", "flv" };
            TypeConfig["Flash"].DeniedExtensions = new string[] { };
            TypeConfig["Flash"].FilesPath = UserFilesPath;

            TypeConfig["Media"].AllowedExtensions = new string[] { "aiff", "asf", "avi", "bmp", "fla", "flv", "gif", "jpeg", "jpg", "mid", "mov", "mp3", "mp4", "mpc", "mpeg", "mpg", "png", "qt", "ram", "rm", "rmi", "rmvb", "swf", "tif", "tiff", "wav", "wma", "wmv" };
            TypeConfig["Media"].DeniedExtensions = new string[] { };
            TypeConfig["Media"].FilesPath = UserFilesPath;
        }

        #region 检查上传文件是否合乎规则
        private bool CheckIsTypeAllowed(string typeName)
        {
            return (System.Array.IndexOf(this.AllowedTypes, typeName) >= 0);
        }

        private bool CheckIsNonHtmlExtension(string extension)
        {
            return (this.HtmlExtensions.Length == 0 || !Util.ArrayContains(this.HtmlExtensions, extension, System.Collections.CaseInsensitiveComparer.DefaultInvariant));
        }

        private bool CheckNonHtmlFile(HttpPostedFileBase file)
        {
            byte[] buffer = new byte[1024];
            file.InputStream.Read(buffer, 0, 1024);

            string firstKB = System.Text.ASCIIEncoding.ASCII.GetString(buffer);

            if (Regex.IsMatch(firstKB, @"<!DOCTYPE\W*X?HTML", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            if (Regex.IsMatch(firstKB, @"<(?:body|head|html|img|pre|script|table|title)", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            //type = javascript
            if (Regex.IsMatch(firstKB, @"type\s*=\s*[\'""]?\s*(?:\w*/)?(?:ecma|java)", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            //href = javascript
            //src = javascript
            //data = javascript
            if (Regex.IsMatch(firstKB, @"(?:href|src|data)\s*=\s*[\'""]?\s*(?:ecma|java)script:", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            //url(javascript
            if (Regex.IsMatch(firstKB, @"url\s*\(\s*[\'""]?\s*(?:ecma|java)script:", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            return true;
        }
        #endregion

        private string ServerMapFolder(string resourceType, string folderPath, bool isQuickUpload)
        {
            TypeConfig typeConfig = this.TypeConfig[resourceType];

            // Get the resource type directory.
            string sResourceTypePath = HttpContext.Current.Server.MapPath(typeConfig.FilesPath);

            // Ensure that the directory exists.
            Util.CreateDirectory(sResourceTypePath);

            // Return the resource type directory combined with the required path.
            return System.IO.Path.Combine(sResourceTypePath, folderPath.TrimStart('/'));
        }

        internal string FileUpload(HttpPostedFileBase oFile, string resourceType, string currentFolder, bool isQuickUpload)
        {
            string strValue = string.Empty;

            if (resourceType == null)
            {
                strValue = SendFileUploadResponse(1, true, "", "", "无效的请求！");
            }
            else
            {
                // Check if it is an allowed type.
                if (!CheckIsTypeAllowed(resourceType))
                {
                    strValue = SendFileUploadResponse(1, true, "", "", "无效的资源类型请求！");
                }
                else
                {
                    string sFileName = "";

                    if (oFile == null)
                    {
                        strValue = SendFileUploadResponse(202, isQuickUpload, "", "", "请选择您要上传的文件！");
                    }
                    else
                    {
                        // Map the virtual path to the local server path.
                        string sServerDir = this.ServerMapFolder(resourceType, currentFolder, isQuickUpload);

                        // Get the uploaded file name.
                        sFileName = System.IO.Path.GetFileName(oFile.FileName);
                        sFileName = Util.SanitizeFileName(sFileName);

                        string sExtension = System.IO.Path.GetExtension(oFile.FileName);
                        sExtension = sExtension.TrimStart('.');

                        if (!this.TypeConfig[resourceType].CheckIsAllowedExtension(sExtension))
                        {
                            strValue = SendFileUploadResponse(202, isQuickUpload, "", "", "您只能上传类型为：" + Util.ArrayToSrting(this.TypeConfig[resourceType].AllowedExtensions) + " 的文件！");
                        }
                        else
                        {
                            if (this.CheckIsNonHtmlExtension(sExtension) && !this.CheckNonHtmlFile(oFile))
                            {
                                strValue = SendFileUploadResponse(202, isQuickUpload, "", "", "您不能上传类型为：" + Util.ArrayToSrting(this.TypeConfig[resourceType].DeniedExtensions) + " 的文件！");
                            }
                            else
                            {
                                int iErrorNumber = 0;
                                int iCounter = 0;

                                while (true)
                                {
                                    string sFilePath = System.IO.Path.Combine(sServerDir, sFileName);

                                    if (System.IO.File.Exists(sFilePath))
                                    {
                                        iCounter++;
                                        sFileName =
                                            System.IO.Path.GetFileNameWithoutExtension(oFile.FileName) +
                                            "(" + iCounter + ")." +
                                            sExtension;

                                        iErrorNumber = 201;
                                    }
                                    else
                                    {
                                        oFile.SaveAs(sFilePath);
                                        break;
                                    }
                                }

                                TypeConfig typeConfig = this.TypeConfig[resourceType];

                                string sFileUrl = typeConfig.FilesPath + "/" + sFileName;

                                strValue = SendFileUploadResponse(iErrorNumber, isQuickUpload, sFileUrl, sFileName, "上传成功！");
                            }
                        }
                    }
                }
            }

            return strValue;
        }

        #region SendFileUploadResponse
        private string SendFileUploadResponse(int errorNumber, bool isQuickUpload, string fileUrl, string fileName, string customMsg)
        {
            if (isQuickUpload)
            {
                StringBuilder strJs = new StringBuilder();

                strJs.Append("<script type=\"text/javascript\">");

                // Minified version of the document.domain automatic fix script.
                // The original script can be found at _dev/domain_fix_template.js
                strJs.Append(@"(function(){var d=document.domain;while (true){try{var A=window.top.opener.document.domain;break;}catch(e) {};d=d.replace(/.*?(?:\.|$)/,'');if (d.length==0) break;try{document.domain=d;}catch (e){break;}}})();");

                if (isQuickUpload)
                    strJs.Append("window.parent.OnUploadCompleted(" + errorNumber + ",'" + fileUrl.Replace("'", "\\'") + "','" + fileName.Replace("'", "\\'") + "','" + customMsg.Replace("'", "\\'") + "') ;");
                else
                    strJs.Append("window.parent.frames['frmUpload'].OnUploadCompleted(" + errorNumber + ",'" + fileName.Replace("'", "\\'") + "') ;");

                strJs.Append("</script>");

                return strJs.ToString();
            }
            else
            {
                return customMsg;
            }
        }
        #endregion

    }
}
